/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import CoreMotion
import Flutter

class AccelerometerStreamHandler: NSObject, FlutterStreamHandler {
    private let motionManager = CMMotionManager()
    private var callback: ((Int) -> Void)?
    private var eventSink: FlutterEventSink?
    private let queue = OperationQueue()
    private var lastOrientation = -1

    func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
        eventSink = events
        if motionManager.isAccelerometerAvailable {
            motionManager.startAccelerometerUpdates(to: queue) { data, _ in if data != nil {}
            }
        }
        return nil
    }

    func onCancel(withArguments arguments: Any?) -> FlutterError? {
        eventSink = nil
        motionManager.stopAccelerometerUpdates()
        return nil
    }

    func setUpdateInterval(_ interval: TimeInterval) {
        motionManager.accelerometerUpdateInterval = interval
    }

    func addOrientationChangeListener(callback: @escaping (Int) -> Void) {
        self.callback = callback
    }

    func removeOrientationChangeListener() {
        callback = nil
    }

    private func onSensorChanged(event: CMAccelerometerData) {
        let values = event.acceleration
        var orientation = -1

        let X = -values.x
        let Y = -values.y
        let Z = -values.z

        let magnitude = X * X + Y * Y
        var angle = -1
        if magnitude * 4 >= Z * Z {
            let oneEightyOverPi = 57.29577957855
            angle = 90 - Int(round(atan2(-Y, X) * oneEightyOverPi))
            angle = angle >= 0 ? angle % 360 : angle % 360 + 360
        }

        if angle >= 0 && (angle <= 30 || angle >= 330) {
            orientation = 0
        } else if angle >= 60 && angle <= 120 {
            orientation = 1
        } else if angle >= 150 && angle <= 210 {
            orientation = 2
        } else if angle >= 240 && angle <= 300 {
            orientation = 3
        }

        if lastOrientation != orientation {
            lastOrientation = orientation
            callback!(lastOrientation)
            eventSink!(lastOrientation)
        }
    }
}
